<?php

namespace fastphp;

use Exception;
use Smarty;

/**
 * 视图基类 - 符合 MVC 规范的视图实现
 */
class View
{
    /**
     * 模板引擎实例
     * @var Smarty
     */
    protected $engine;
    
    /**
     * 存储视图变量
     * @var array
     */
    protected $variables = [];
    
    /**
     * 控制器名称
     * @var string
     */
    protected $controller;
    
    /**
     * 操作方法名称
     * @var string
     */
    protected $action;
    
    /**
     * 配置参数
     * @var array
     */
    protected $config = [];

    /**
     * 构造函数 - 支持依赖注入模板引擎
     * 
     * @param string $controller 控制器名称
     * @param string $action 操作方法名称
     * @param mixed $engine 可选的模板引擎实例，默认为 null 时创建 Smarty 实例
     * @param array $config 可选的配置参数
     */
    public function __construct($controller, $action, $engine = null, array $config = [])
    {
        $this->controller = $controller;
        $this->action = $action;
        
        // 配置键名映射，确保与config.php中的配置兼容
        $mappedConfig = $config;
        if (isset($mappedConfig['suffix'])) {
            $mappedConfig['template_suffix'] = $mappedConfig['suffix'];
            unset($mappedConfig['suffix']);
        }
        
        // 合并默认配置与映射后的配置
        $this->config = array_merge($this->getDefaultConfig(), $mappedConfig);
        
        // 初始化模板引擎 - 支持依赖注入
        $this->engine = $engine ?: $this->createDefaultEngine();
    }
    
    /**
     * 获取默认配置
     * 
     * @return array 默认配置数组
     */
    protected function getDefaultConfig()
    {
        // 直接使用默认值，不再依赖未定义的常量
        return [
            'debugging' => false,
            'caching' => false,
            'cache_lifetime' => 3600,
            'template_dir' => APP_PATH . 'view/',
            'compile_dir' => RUNTIME_PATH . 'templates_c/',
            'config_dir' => APP_PATH . 'config/',
            'cache_dir' => RUNTIME_PATH . 'cache/',
            'left_delimiter' => '{$',
            'right_delimiter' => '}',
            'template_suffix' => '.tpl'
        ];
    }
    
    /**
     * 创建默认的 Smarty 模板引擎实例
     * 
     * @return Smarty Smarty 实例
     * @throws Exception 当初始化失败时抛出异常
     */
    protected function createDefaultEngine()
    {
        try {
            $smarty = new Smarty();
            
            // 设置 Smarty 配置
            $smarty->debugging = $this->config['debugging'];
            $smarty->caching = $this->config['caching'];
            $smarty->cache_lifetime = $this->config['cache_lifetime'];
            
            // 确保目录存在
            $this->ensureDirectoryExists($this->config['cache_dir']);
            $this->ensureDirectoryExists($this->config['compile_dir']);
            
            // 设置目录路径
            $smarty->setTemplateDir($this->config['template_dir']);
            $smarty->setCompileDir($this->config['compile_dir']);
            $smarty->setConfigDir($this->config['config_dir']);
            $smarty->setCacheDir($this->config['cache_dir']);
            
            // 设置定界符
            $smarty->left_delimiter = $this->config['left_delimiter'];
            $smarty->right_delimiter = $this->config['right_delimiter'];
            
            return $smarty;
        } catch (Exception $e) {
            throw new Exception("Failed to initialize template engine: " . $e->getMessage());
        }
    }
    
    /**
     * 确保目录存在，如果不存在则创建
     * 
     * @param string $dir 目录路径
     * @throws Exception 当无法创建目录时抛出异常
     */
    protected function ensureDirectoryExists($dir)
    {
        if (!is_dir($dir)) {
            if (!mkdir($dir, 0755, true)) {
                throw new Exception("Failed to create directory: {$dir}");
            }
        }
    }

    /**
     * 设置单个变量
     * 
     * @param string $name 变量名
     * @param mixed $value 变量值
     * @return $this 支持链式调用
     */
    public function set($name, $value)
    {
        $this->variables[$name] = $value;
        $this->engine->assign($name, $value);
        return $this;
    }
    
    /**
     * 批量设置变量
     * 
     * @param array $data 变量数组，键为变量名，值为变量值
     * @return $this 支持链式调用
     */
    public function with(array $data)
    {
        foreach ($data as $name => $value) {
            $this->set($name, $value);
        }
        return $this;
    }
    
    /**
     * 获取已设置的变量值
     * 
     * @param string $name 变量名
     * @param mixed $default 默认值，当变量不存在时返回
     * @return mixed 变量值或默认值
     */
    public function get($name, $default = null)
    {
        return isset($this->variables[$name]) ? $this->variables[$name] : $default;
    }
    
    /**
     * 获取所有已设置的变量
     * 
     * @return array 所有变量数组
     */
    public function all()
    {
        return $this->variables;
    }
    
    /**
     * 清除指定变量
     * 
     * @param string $name 变量名
     * @return $this 支持链式调用
     */
    public function forget($name)
    {
        if (isset($this->variables[$name])) {
            unset($this->variables[$name]);
            // 如果使用 Smarty，可以重置该变量
            $this->engine->assign($name, null);
        }
        return $this;
    }
    
    /**
     * 清除所有变量
     * 
     * @return $this 支持链式调用
     */
    public function clear()
    {
        $this->variables = [];
        // 重置 Smarty 变量
        if (method_exists($this->engine, 'clearAllAssign')) {
            $this->engine->clearAllAssign();
        }
        return $this;
    }

    /**
     * 渲染并显示模板
     * 
     * @param string|null $templatePath 模板路径，默认为 controller/action
     * @return void
     * @throws Exception 当模板不存在时抛出异常
     */
    public function render($templatePath = null)
    {
        $template = $templatePath ?: $this->controller . '/' . $this->action;
        $template .= $this->config['template_suffix'];
        
        $fullPath = $this->config['template_dir'] . $template;
        if (!file_exists($fullPath)) {
            throw new Exception("Template not found: {$template} ({$fullPath})");
        }
        
        $this->engine->display($template);
    }
    
    /**
     * 渲染模板并返回内容（不直接输出）
     * 
     * @param string|null $templatePath 模板路径
     * @return string 渲染后的模板内容
     * @throws Exception 当模板不存在时抛出异常
     */
    public function fetch($templatePath = null)
    {
        $template = $templatePath ?: $this->controller . '/' . $this->action;
        $template .= $this->config['template_suffix'];
        
        $fullPath = $this->config['template_dir'] . $template;
        if (!file_exists($fullPath)) {
            throw new Exception("Template not found: {$template} ({$fullPath})");
        }
        
        return $this->engine->fetch($template);
    }
    
    /**
     * 获取模板引擎实例
     * 
     * @return mixed 模板引擎实例
     */
    public function getEngine()
    {
        return $this->engine;
    }
    
    /**
     * 设置模板引擎实例
     * 
     * @param mixed $engine 模板引擎实例
     * @return $this 支持链式调用
     */
    public function setEngine($engine)
    {
        $this->engine = $engine;
        // 重新分配所有变量到新引擎
        foreach ($this->variables as $name => $value) {
            $this->engine->assign($name, $value);
        }
        return $this;
    }
}
